嗨 大家好 我是一路爬坡的阿肥
阿肥竟然撐過第三個禮拜了!
真的太感動了嗚嗚
希望可以撐到最後!
今天阿肥又要講跟設計模式沒什麼直接相關的主題啦(被揍)。雖然沒直接的關連,但是阿肥覺得,在軟體開發中,這是跟學好設計模式同等重要的!那就是 要做測試 。
試想在某專案中,你心血來潮地用了某種設計模式開發出資料模型,但是沒有先自行驗證資料邏輯是否有誤,建立出來的物件是否有符合期待的屬性,操作方法是否為正確的行為...等等。如果到了實際開發主程式時,才用手動的方式慢慢測。這樣不但影響了開發效率,開發人員對自己程式碼的信心度也會降低,日後可能光是修bug就佔了日常一半的工作時間。
很多開發人員或許都有經過這樣的惡性循環:為了減少開發時間不寫測試,結果QA階段到上線階段花大半時間改bug,日後維護程式因為沒有做測試,要更動邏輯的部分又花更久的時間在重構程式...。這樣的開發日常妳/你喜歡嗎?
極限開發(XP),是敏捷軟體開發 (註1) 中最著名的一個方法論。強調的是將任務/系統細分為可以在較短週期解決的一個個子任務/模組,並且強調要做測試、重視程式碼的質量和及早發現問題。
XP主要會有這些實踐原則:
阿肥的團隊最近舉辦的的讀書會,主題就是這本書《Mastering React Test-Driven Development, 精通React測試驅動開發》
這本書是目前少數是介紹React專案中,如何導入TDD流程來開發。在觀念解釋,和程式演示都相當清楚易懂。第一次接觸React的新手也是相當推薦從這本入門喔。
接著就藉由這本的第一章內容來認識React的TDD吧!
有些人可能是從 create-react-app
clone下來開始。但是作者認為這與極限開發中提及到的 YAGNI(You aren't gonna need it) 原則相抵觸。我們應該確定使用到的才加入到專案中,一來我們可以掌握專案使用到的外部資源; 二來也不會專案中存在過多無用的東西。
TDD的精神之一就是要先寫測試,所以先準備好測試環境,作者推薦以Jest作為React專案的測試框架。
所以我們先來裝相關套件。以本範例專案是用 Typescript 開發的話,我們需要另外裝相關的定義檔跟loader:
yarn add -DW jest @types/ject ts-jest
接著在根目錄下新增 jest.config.js
,根據專案所需設定
module.exports = {
//...
globals: {
'ts-jest': {
extends: './babel.config.js',
},
},
moduleFileExtensions: ['ts', 'tsx', 'js'],
//...
testMatch: ['**/__tests__/*.+(ts|tsx|js)', '**/*.test.+(ts|tsx|js)'],
transform: {
'^.+\\.(ts|tsx)$': 'ts-jest',
},
//...
}
環境準備好之後,就可以開始寫第一個測試囉!
作者的習慣是將測試程式與產品程式分離,不過這就看個人的喜好,阿肥目前是將測試檔跟元件目錄放在一起,這樣匯入與查詢相關程式會比較方便。檔案名稱通常命名為 XXX.test.ts(x)
,能符合設定檔中的 testMatch
的正規即可。
describe
跟 it
所以看起來會像這樣:
describe("元件名稱", () => {
it("單元測試的描述", () => {
//...測試內容
});
});
紅綠測試是指,一開始先寫好單元測試的內容,包括傳入props給元件,渲染成DOM,以及驗證期待的結果。這時候由於還沒實作元件,所以執行測試時,會出現紅字並提示哪個驗證不符預期結果。 然後再去實作功能的細節,讓紅字能變成綠字通過。透過這樣的循環達到TDD的開發準則。
不過我們是用 Typescript 開發。如果匯入一個不存在的元件的話就會報錯。所以我們可以先建立好元件基本的架構、props的介面宣告等。之後針對實際要開發的功能再進行紅綠測試的流程。
ComponentA.tsx
export const ComponentA: React.FC<I_Props_ComponentA> = ({
//...
}) => {
const handleSubmit = e => {
e.preventDefault();
};
return (
<div>
<form onSubmit={handleSubmit} id="componentAForm"></form>
</div>
);
};
ComponentA.test.tsx
let container;
//每個測試案例前執行(更換element,Reseting)
beforeEach(() => {
container = document.createElement("div");
});
//提取重複程式
const render = component => ReactDOM.render(component, container);
const form = (id: string) => container.querySelector(`form[id="${id}"]`);
describe("ComponentA", () => {
it("產生表單", () => {
// Arrange: 安排,產生目標的測試實體或資料
render(<ComponentA onSubmit={null} />);
// Assert: 斷言,檢查結果是否為預期
expect(form("componentAForm")).not.toBeNull();
});
});
好的測試需要清楚、獨立的條列出:
render(<ComponentA onSubmit={null} />);
act(() => { button.dispatchEvent(new MouseEvent('click', {bubbles: true})); });
expect(form("componentAForm")).not.toBeNull();
今天講的內容只是測試的冰山一角而已。如果下定決心跟阿肥一樣想學好這塊的話,可以看參考資料的連結,並且開始動手做。下一次的鐵人賽阿肥或許會進一步介紹這本書,請大家敬請期待囉!
註1: 為了解決許多公司的軟體團隊在開發過程中浮現的問題陷入泥沼,一批業界專家概括出了一些可讓團隊具有快速工作、響應變化能力的價值觀和原則,並自稱為敏捷聯盟。目前敏捷開發的方法論有:SCRUM,Crystal,特徵驅動軟體開發(Feature Driven Development,簡稱FDD),自適應軟體開發(Adaptive Software Development,簡稱ASD),以及今天提到的極限開發(eXtreme Programming,簡稱XP)。